<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Prototype object browser</title>
    <style type="text/css" media="screen">
      body {
        font-family: Lucida Grande, Verdana, sans-serif;
        font-size: 13px;
      }
      
      .inspector {
        margin: 1%;
        float: left;
        width: 31%;
        border: 1px solid #ccc;
        background-color: white;
      }
      
      .inspector h2 {
        font-size: 13px;
        margin: 0;
        text-align: center;
        padding: 5px;
        background-color: #e6e6e6;
        border-bottom: 1px solid #999;
      }
      
      .inspector ul {
        height: 200px;
        overflow: auto;
        margin: 0;
        padding-left: 0;
      }
      
      .inspector li {
        cursor: pointer;
        list-style-type: none;
        padding: 2px 5px 2px 30px;
        color: #333;
      }
      
      .inspector li.selected {
        background-color: #888;
        color: #fff;
      }
      
      .inspector.active li.selected {
        background-color: #1a76fd;
        color: #fff;
      }
      
      #path, #value {
        width: 97%;
        margin: 1%;
      }

      #path {
        margin-bottom: 0;
        border: 1px solid #ccc;
        border-bottom: 1px solid #999;
        background-color: #e6e6e6;
      }
      
      #value {
        margin-top: 0;
        border: 1px solid #ccc;
        border-top: none;
        overflow: auto;
      }
      
      #path_content, #value_content {
        display: block;
        padding: 15px 30px 15px 30px;
      }
      
    </style>    
    <script type="text/javascript" src="../dist/prototype.js"></script>
    <script type="text/javascript">
      var Browser = Class.create();
      Browser.prototype = {
        initialize: function(element, name, value, options) {
          this.element = $(element);
          this.name    = name;
          this.value   = value;
          this.history = [];
          Object.extend(this, options || {});
          this.reset();
        },
        
        reset: function() {
          this.go(this.name, this.value);
        },
        
        refresh: function() {
          var children = $A(this.element.childNodes),
              history  = this.history.toArray(),
              elements = history.slice(-3).pluck('element');
                  
          children.each(function(element) {
            if (element && !elements.include(element))
              this.element.removeChild(element);
          }.bind(this));
          
          children = $A(this.element.childNodes);
          
          elements.each(function(element, index) {
            Element.removeClassName(element, 'active');
            var child = children[index];
            if (!child)
              this.element.appendChild(element);
            else if (!element.parentNode)
              this.element.insertBefore(element, child);
          }.bind(this));
          
          this.setTitle();
          this.setValue();
        },
        
        setTitle: function() {
          if (this.titleElement)
            this.titleElement.innerHTML =
              this.history.pluck('name').invoke('escapeHTML').join('.');
        },
        
        setValue: function() {
          if (this.valueElement)
            this.valueElement.innerHTML = 
              this.currentValue().escapeHTML() + '&nbsp;';
        },
        
        currentValue: function() {
          try {
            return Object.inspect(this.current());
          } catch (e) {
            return '(Internal Function)';
          }
        },
        
        current: function() {
          return this.history.last().value;
        },
        
        go: function(name, value) {
          var from = this.history.last();
          this.history.push(new Inspector(this, name, value));
          this.refresh();
          if (from) 
            Element.addClassName(from.element, 'active');
        }
      }
      
      var Inspector = Class.create();
      Inspector.prototype = {
        initialize: function(browser, name, value) {
          this.browser = browser;
          this.name    = name;
          this.value   = value;
          this.id      = 'inspector_' + new Date().getTime();
          this.history = this.browser.history.toArray();
          this.history.push(this);
          this.createElement();
          this.populate();
        },
        
        properties: function() {
          var properties = [];
          for (var property in this.value)
            properties.push(property);
          properties.sort();
          return properties;
        },
        
        createElement: function() {
          var element = document.createElement('div');
          element.className = 'inspector';
          element.id = this.id;
          this.element = element;
          
          var title = document.createElement('h2');
          title.innerHTML = this.name.toString().escapeHTML();
          this.titleElement = title;
          
          var list = document.createElement('ul');
          this.listElement = list;
          
          element.appendChild(title);
          element.appendChild(list);          
        },
        
        populate: function() {
          this.properties().each(function(property) {
            var li = document.createElement('li');
            li.innerHTML = property.toString().escapeHTML();
            li.onclick   = this.select.bind(this, li);
            li._property = property;
            this.listElement.appendChild(li);
          }.bind(this));
        },
        
        select: function(element) {
          this.unselect();
          Element.addClassName(element, 'selected');
          this.selectedProperty = element;
          this.browser.history = this.history.toArray();
          this.browser.go(element._property, this.value[element._property]);
        },
        
        unselect: function() {
          if (this.selectedProperty)
            Element.removeClassName(this.selectedProperty, 'selected');
          this.selectedProperty = null;
        }
      }
    </script>
  </head>
  <body>
    <div id="browser_wrapper">
      <div id="browser"></div>
      <div style="clear: left"></div>
    </div>
    <h1 id="path"><span id="path_content"></span></h1>
    <pre id="value"><div id="value_content"></div></pre>
    <script type="text/javascript">
      new Browser('browser', 'window', window, {titleElement: $('path_content'), valueElement: $('value_content')})
    </script>
  </body>
</html>
